#include "TileManager.h"
#include "TileWalker.h"
#include "ResourceSystem.h"
#include <sstream>
#include <iostream>
#include <string>
#include "Debug.h"

TileManager::TileManager()
{
	window = NULL;
	camera = NULL;
	mapsize  = sf::Vector2i(5,5); 
	tilesize = sf::Vector2f(96,48);
}

void TileManager::LoadLevel()
{
	m_tileGrid.resize(mapsize.x);
	m_tiles.reserve(mapsize.x*mapsize.y);
	
	for(uint16 i=0; i<m_tileGrid.size(); i++) {
		m_tileGrid[i].resize(mapsize.y);
	}

	for(int col = 0; col < mapsize.x; col++) {
		for(int row = 0; row< mapsize.y; row++){
			Tile* tile = new Tile;
			switch(rand()%2) {
				case 0: tile->Load("terrain001.bmp"); break;
				case 1: tile->Load("terrain002.bmp"); break;
				default:tile->Load("terrain001.bmp"); break;
			}
			sf::Vector2f loc = TilePlotter::PlotTile(row,col);
			if(camera) {
				loc.x -= camera->x(); loc.y -= camera->y();
			}
			tile->SetPos(loc);
			m_tiles.push_back(tile);
			m_tileGrid[col][row] = 0;
		}
	}
	std::cout << "size of a tile is: " << sizeof(Tile) << std::endl;
	mmap.Load(ResourceSystem::GetImage("mousemap.bmp"));
}

void TileManager::Draw()
{
	sf::Sprite test;
	sf::Sprite temp;
	test.SetImage(*ResourceSystem::GetImage("stables.bmp", sf::Color::Black, false));
	if(!window) {
		sLog.outDebug("TileManager::Draw(): window is NULL! Can't draw!");
		return;
	}
	int i = 0;
	//calculate which tiles to draw:
	for(int j=0; j<(int)m_tiles.size(); j++) {
		Tile* tile = m_tiles.at(j);

		if(camera && !camera->IsOnCamera(tile->GetPos(), tilesize)) 
			continue;

		sf::Vector2f loc = tile->GetPos();
		//change location relative to the camera while drawing
		if(camera) {
			loc.x -= camera->x(); 
			loc.y -= camera->y();
		}

		temp.SetPosition(loc);
		temp.SetImage(tile->GetImage());

		window->Draw(temp);
		++i;

	}

	sf::String sprites;
	sprites.SetSize(24);

	//crash alert here!
	sf::Vector2f loc = m_tiles.at(5)->GetPos();
	if(camera) {
		loc.x -= camera->x(); 
		loc.y -= camera->y();
	}
	test.SetPosition(loc);
	window->Draw(test);

	//crash alert here! this is debug only
	loc = m_tiles.at(7)->GetPos();
	if(camera) {
		loc.x -= camera->x(); 
		loc.y -= camera->y();
	}

	//this will crap on my resource system! this image wont get freed!
	test.SetImage(*ResourceSystem::GetImage("barracks.bmp",sf::Color(255,0,255),false));
	test.SetPosition(loc);
	//window->Draw(test);

	std::stringstream s;
	s << "Sprites rendered: " << i << "    Width: " << mapsize.x*96 << "  Height: " << mapsize.y*48;
	sprites.SetText(s.str());
	window->Draw(sprites);

	s.str(std::string());
	if(camera) {
		s << "Cam pos: " << camera->x() << " | " << camera->y();
	}
	sprites.SetText(s.str());
	sprites.SetPosition(0,30);
	window->Draw(sprites);


}

void TileManager::FreeLevel()
{
	for(int i=0; i<(int)m_tiles.size();i++) {
		delete m_tiles[i];
	}
	m_tiles.clear();
	for(uint16 i=0; i<m_tileGrid.size();i++) {
		m_tileGrid[i].clear();
	}
	m_tileGrid.clear();
}
int TileManager::WorldToIso2(float x, float y)
{
	return WorldToIso2(sf::Vector2f(x,y));
}

//fixed I think
sf::Vector2i TileManager::WorldToIso(const sf::Vector2f& pos )
{
	//plot the 0,0 tile and move from there until you reach the desired mousemap tile
	sf::Vector2i mousePos;
	//convert to world coords
	mousePos.x = (int) pos.x + (int)camera->x();	
	mousePos.y = (int) pos.y + (int)camera->y(); 

	sf::Vector2f curTilePos = TilePlotter::PlotTile(0,0);

	sf::Vector2i curTile;
	curTile.x = 0;
	curTile.y = 0;

	//move from the 0,0 mmap tile on the x-axis until you find the right tile 
	//move left(WEST) on the x-axis until you get to the mousemap tile that contains the mousepos
	while((float)mousePos.x < curTilePos.x) {		
		TileWalker::Move(curTile,ISO_WEST);
		curTilePos = TilePlotter::PlotTile(curTile);
	}
	//move left(EAST) on the x-axis until you get to the mousemap tile that contains the mousepos
	while((float)mousePos.x > curTilePos.x + tilesize.x) {
		TileWalker::Move(curTile, ISO_EAST);
		curTilePos = TilePlotter::PlotTile(curTile);
	}
	//move up (NORTH) on the y-axis until you get to the mousemap tile that contains the mousepos
	while((float)mousePos.y < curTilePos.y) {		
		TileWalker::Move(curTile, ISO_NORTH);
		curTilePos = TilePlotter::PlotTile(curTile);
	}
	//move up (SOUTH) on the y-axis until you get to the mousemap tile that contains the mousepos
	while((float)mousePos.y > curTilePos.y + tilesize.y) {
		TileWalker::Move(curTile, ISO_SOUTH);
		curTilePos = TilePlotter::PlotTile(curTile);
	}
	//now you should have the MouseMap Tile that contains the mousepos...
	
	//find the relative mouse cursor pos on the current tile
	sf::Vector2i relativeMousePos;
	relativeMousePos.x = mousePos.x - (int)curTilePos.x;
	relativeMousePos.y = mousePos.y - (int)curTilePos.y;

	//avoid crashing when trying to access memory above 48...
	if(relativeMousePos.x >= 96) relativeMousePos.x = 95;
	if(relativeMousePos.y >= 48) relativeMousePos.y = 47;

	//now check the MouseMap lookup table to see on which tile the click happened
	switch(mmap.Lookup(relativeMousePos.x, relativeMousePos.y)) {
		case MM_CENTER: break;
		case MM_NE:	TileWalker::Move(curTile, ISO_NORTHEAST); break;
		case MM_NW: TileWalker::Move(curTile, ISO_NORTHWEST); break;
		case MM_SE: TileWalker::Move(curTile, ISO_SOUTHEAST); break;
		case MM_SW: TileWalker::Move(curTile, ISO_SOUTHWEST); break;
		default:
			std::cout << "TileManager::WorldToIso(): Unhandled case in MouseMap lookup switch" << std::endl;
	}
	if(curTile.x < 0 || curTile.y < 0) {
		std::cout << "Invalid tile[" << curTile.y << "]["<< curTile.x << "] ->"<< "at pos: " << mousePos.y << " | " << mousePos.x << std::endl;
		return sf::Vector2i(-1,-1);
	}
	if(curTile.x > mapsize.x || curTile.y > mapsize.y) {
		std::cout << "Invalid tile[" << curTile.y << "]["<< curTile.x << "] ->"<< "at pos: " << mousePos.y << " | " << mousePos.x << std::endl;
		return sf::Vector2i(-1,-1);
	}
	#ifdef _DEBUG
	std::cout << "Tile selected: " << curTile.y << "|" << curTile.x << std::endl;
	#endif
	return curTile;
}

sf::Vector2i TileManager::WorldToIso(float x, float y)
{
	return WorldToIso(sf::Vector2f(x,y));
}

//fixed
int TileManager::WorldToIso2(const sf::Vector2f& pos )
{
	//plot the 0,0 tile and move from there until you reach the desired mousemap tile
	sf::Vector2i mousePos;
	//convert to world coords
	mousePos.x = (int) pos.x + (int)camera->x();	
	mousePos.y = (int) pos.y + (int)camera->y(); 

	sf::Vector2f curTilePos = TilePlotter::PlotTile(0,0);

	sf::Vector2i curTile;
	curTile.x = 0;
	curTile.y = 0;

	//move from the 0,0 mmap tile on the x-axis until you find the right tile 
	//move left(WEST) on the x-axis until you get to the mousemap tile that contains the mousepos
	while((float)mousePos.x < curTilePos.x) {		
		TileWalker::Move(curTile,ISO_WEST);
		curTilePos = TilePlotter::PlotTile(curTile);
	}
	//move left(EAST) on the x-axis until you get to the mousemap tile that contains the mousepos
	while((float)mousePos.x > curTilePos.x + tilesize.x) {
		TileWalker::Move(curTile, ISO_EAST);
		curTilePos = TilePlotter::PlotTile(curTile);
	}
	//move up (NORTH) on the y-axis until you get to the mousemap tile that contains the mousepos
	while((float)mousePos.y < curTilePos.y) {		
		TileWalker::Move(curTile, ISO_NORTH);
		curTilePos = TilePlotter::PlotTile(curTile);
	}
	//move up (SOUTH) on the y-axis until you get to the mousemap tile that contains the mousepos
	while((float)mousePos.y > curTilePos.y + tilesize.y) {
		TileWalker::Move(curTile, ISO_SOUTH);
		curTilePos = TilePlotter::PlotTile(curTile);
	}
	//now you should have the MouseMap Tile that contains the mousepos...

	//find the relative mouse cursor pos on the current tile
	sf::Vector2i relativeMousePos;
	relativeMousePos.x = mousePos.x - (int)curTilePos.x;
	relativeMousePos.y = mousePos.y - (int)curTilePos.y;

	//avoid crashing when trying to access memory above 48...
	if(relativeMousePos.x >= 96) relativeMousePos.x = 95;
	if(relativeMousePos.y >= 48) relativeMousePos.y = 47;

	//now check the MouseMap lookup table to see on which tile the click happened
	switch(mmap.Lookup(relativeMousePos.x, relativeMousePos.y)) {
		case MM_CENTER: break;
		case MM_NE:	TileWalker::Move(curTile, ISO_NORTHEAST); break;
		case MM_NW: TileWalker::Move(curTile, ISO_NORTHWEST); break;
		case MM_SE: TileWalker::Move(curTile, ISO_SOUTHEAST); break;
		case MM_SW: TileWalker::Move(curTile, ISO_SOUTHWEST); break;
		default:
			std::cout << "TileManager::WorldToIso(): Unhandled case in MouseMap lookup switch" << std::endl;
	}
	if(curTile.x < 0 || curTile.y < 0) {

		std::cout << "Invalid tile[" << curTile.y << "]["<< curTile.x << "] ->"<< "at pos: " << mousePos.y << " | " << mousePos.x << std::endl;
		return -1;
	}
	if(curTile.x >= mapsize.x || curTile.y >= mapsize.y) {
		std::cout << "Invalid tile[" << curTile.y << "]["<< curTile.x << "] ->"<< "at pos: " << mousePos.y << " | " << mousePos.x << std::endl;
		return -1;
	}
	#ifdef _DEBUG
	std::cout << "Tile selected: " << curTile.y << "|" << curTile.x << std::endl;
	#endif
	return curTile.x*mapsize.x+curTile.y;
}

TileManager::~TileManager()
{
	FreeLevel();
	ResourceSystem::FreeImage("barracks.bmp");
	ResourceSystem::FreeImage("stables.bmp");
}

//reloads level!
void TileManager::SetMapSize( int w, int h )
{
	mapsize = sf::Vector2i(w,h);

	TilePlotter::SetTileSize(tilesize.x, tilesize.y);
	TilePlotter::SetMapSize(mapsize);

	//reload level
	FreeLevel();
	LoadLevel();
}